package com.yanqu.road.server.gameplayer.module.activity.yqhotel;

import com.yanqu.road.dao.impl.activity.yqhotel.YqHotelUserDataDaoImpl;
import com.yanqu.road.entity.activity.ActivityInfo;

import com.yanqu.road.entity.activity.yqhotel.config.YqHotelCounterConfig;
import com.yanqu.road.entity.activity.yqhotel.config.YqHotelSkillConfig;
import com.yanqu.road.entity.activity.yqhotel.config.YqHotelTitleConfig;
import com.yanqu.road.entity.activity.yqhotel.data.YqHotelBuildingStudent;
import com.yanqu.road.entity.activity.yqhotel.data.YqHotelEventData;
import com.yanqu.road.entity.activity.yqhotel.data.YqHotelStudentData;
import com.yanqu.road.entity.activity.yqhotel.data.YqHotelUserData;
import com.yanqu.road.entity.activity.yqhotel.result.*;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eSexType;
import com.yanqu.road.entity.enums.eSystemId;

import com.yanqu.road.entity.log.yqhotel.LogYqHotelBoss;
import com.yanqu.road.entity.log.yqhotel.LogYqHotelBuilding;
import com.yanqu.road.entity.log.yqhotel.LogYqHotelEvent;
import com.yanqu.road.logic.activity.yqhotel.YQHotelConfig;
import com.yanqu.road.pb.activity.YqHotelProto;
import com.yanqu.road.pb.activity.YqHotelProto;


import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;


import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.NameMgr;

import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.yqhotel.YQHotelDebugMgr;
import com.yanqu.road.server.manger.activity.yqhotel.YqHotelMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;


import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 阳泉酒家 (史莱克)
 */

public class YqHotelModule extends GeneralModule {
    //锁
    private Object locker = new Object();
    //玩家数据
    private YqHotelUserData userData;
    //学员数据
    private Map<Integer, YqHotelStudentData> studentMap = new ConcurrentHashMap<Integer, YqHotelStudentData>();
    //离线流失数量map
    private Map<Integer,Integer> offLineTitleCountMap = new ConcurrentHashMap<>();
    //进入场景设置值 不在场景内为0
    private long sceneUserId;

    //清理学生map debug用
    private Map<Integer,Map<Integer,Long>> clearMap = new ConcurrentHashMap<>();

    //清理等待时间的时候他已经等待了多久
    private Map<Integer,Map<Integer,Long>> clearWaitMap = new ConcurrentHashMap<>();

    //记录变化的上一次是改了什么鬼
    private Map<Integer,String> debugLastWait = new ConcurrentHashMap<>();
    //记录学生历史变化
    private Map<Integer,Map<String,String>> debugHistory = new ConcurrentHashMap<>();

    /**
     * 清除离开学生
     */
    public void clearClearMap(){
        clearMap = new ConcurrentHashMap<>();
    }
    /**
     *  添加离开学生
     */
    public void addClear(long nowTime,int studentId,int buildingId,long clearTime){
        if(!clearMap.containsKey(studentId)){
            clearMap.put(studentId,new ConcurrentHashMap<>());
        }
        if(!clearWaitMap.containsKey(studentId)){
            clearWaitMap.put(studentId,new ConcurrentHashMap<>());
        }
        clearMap.get(studentId).put(buildingId,clearTime);
        Map<Integer,Long> studentEnterTimeMap = getStudentEnterMap(studentId);
        long studentEnterTime = getStudentData(studentId).getStartTime() + studentEnterTimeMap.get(buildingId) + getBeforeBuildingWaitTime(studentId,buildingId);
        clearWaitMap.get(studentId).put(buildingId,nowTime - studentEnterTime);
    }

    public YqHotelModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
//                YQHotelDebugMgr.initDebug(getUserId());
        ActivityInfo activityInfo = YqHotelMgr.getActivityInfo();
        //活动在展示期才拿
        if(ActivityMgr.activityInShowTime(activityInfo)){
            userData = new YqHotelUserDataDaoImpl().getYqHotelUserData(activityInfo.getActivityId(),getUserId());
            if(userData == null){
                initUserData(activityInfo.getActivityId());
            }else{
                studentMap = userData.getStudentMap();
            }
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return false;
    }

    @Override
    public void afterLogin() {
        timerEventMake(false);
        ActivityInfo activityInfo = YqHotelMgr.getActivityInfo();
        if(activityInfo != null){
            if (SystemOpenMgr.systemOpen(player, eSystemId.YQHotel.getValue())) {
                syncConfigData();
                syncUserData();
            }
        }
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()){
                new YqHotelUserDataDaoImpl().add(userData);
            } else if (userData.isUpdateOption()){
                new YqHotelUserDataDaoImpl().update(userData);
            }

        }
        return true;
    }


    public Object getLocker() {
        return locker;
    }

    public void clearOffLineTitleCountMap(){
        offLineTitleCountMap = new ConcurrentHashMap<>();
    }

    public YqHotelUserData getUserData() {
        return userData;
    }

    public void leaveScene(int activityId){
        sceneUserId = 0;
    }

    /**
     * 升级之后清除还没有固定的等待时间重新计算
     * @param levelUpBuildingId 解锁的建筑id
     * @param upLockSeatNum 解锁增加了多少个位置
     */
    private Map<Integer, YqHotelStudentData> clearWaitTimeSeatUp(long nowTime, int levelUpBuildingId, int upLockSeatNum){
        Map<Integer,YqHotelStudentData> changeStudentMap = new ConcurrentHashMap<>();
        Map<Integer,Long> buildingEnterTimeMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        List<Integer> buildingIdList = new ArrayList<>(buildingEnterTimeMap.keySet());
        List<Integer> studentIdList = new ArrayList<>(studentMap.keySet());
        Collections.sort(buildingIdList);
        Collections.reverse(buildingIdList);
        Collections.sort(studentIdList);
        //解锁了多少个位置就有多少人他的等待时间变少了，这个用来减掉那些等待的人的等待时间
        int unlockSeatEnter = 0;
        for(Integer studentId : studentIdList){
            YqHotelStudentData student = studentMap.get(studentId);
            Map<Integer,Long> studentBuildingEnterTimeMap = buildingEnterTimeMap;
            if(student.isQuickStudy()){
                studentBuildingEnterTimeMap = student.getEnterTimeMap();
            }
            for(Integer buildingId : buildingIdList){
                //前面建筑的等待时间不会受影响，只有后面的受影响
                if(levelUpBuildingId > buildingId)continue;
                long studentBeginStudyTime = student.getStartTime() + studentBuildingEnterTimeMap.get(buildingId) + getIncludeBuildingWaitTime(student.getNo(),buildingId);
                long studentEnterCollegeTime = student.getStartTime() + studentBuildingEnterTimeMap.get(buildingId) + getBeforeBuildingWaitTime(student.getNo(),buildingId);
                if(unlockSeatEnter < upLockSeatNum && buildingId == levelUpBuildingId && nowTime > studentEnterCollegeTime && nowTime < studentBeginStudyTime
                        && !isStudentDieBuilding(nowTime,student,buildingId)){
//                    log.error("开坑在等待的第一个学生{},waitMap:{}", student.getNo() ,student.getWaitMap());
                    unlockSeatEnter++;
//                    addHistory(nowTime,studentId);
                    long lessTime = studentBeginStudyTime - nowTime;
                    student.getWaitMap().put(buildingId,student.getWaitMap().get(buildingId) - lessTime);
                    student.setDieInBuilding(-1);
                    student.setDieTime(-1);
                    addChangeStudent(changeStudentMap,student);
//                    addClear(nowTime,studentId,buildingId,student.getWaitMap().get(buildingId) - lessTime);
                }else{
                    //学生已经在排队的且还没排队且到这里不会流失的
                    if(nowTime < studentBeginStudyTime && !isStudentDieBuilding(nowTime,student,buildingId)){
//                        addHistory(nowTime,studentId);
                        student.setWaitTime(buildingId,-1L);
                        student.setDieInBuilding(-1);
                        student.setDieTime(-1);
                        addChangeStudent(changeStudentMap,student);
//                        addClear(nowTime,studentId,buildingId,0L);
                    }
                }
            }
        }
        userData.setStudentMap(studentMap);
        return changeStudentMap;
    }

    private boolean isStudentDieAfterBuilding(YqHotelStudentData student,int buildingId){
        return (student.getDieInBuilding() == -1 || student.getDieInBuilding() > buildingId);
    }

    //升级魂等级的时候要把所有人的没到时间的魂重新算一下//1代表升级坑位的那个技能，2是每个建筑的特殊技能那个
    public YqHotelLevelUpStudentResult levelUp(int buildingId, int type){
        int oLevel = 1;
        Map<Integer, YqHotelStudentData> changeStudentMap = new ConcurrentHashMap<>();
        YqHotelLevelUpStudentResult result = new YqHotelLevelUpStudentResult();
        long nowTime = System.currentTimeMillis();
        mainLogic(nowTime,true);
        if(type == 1){
            int ret = levelUpPre(buildingId);
            if(ret != 0){
                result.setRet(ret);
                return result;
            }
            oLevel = getBuildingLevel(buildingId);
            YqHotelCounterConfig counterConfig = YqHotelMgr.getBuildingConfig(buildingId,oLevel);
            Property reward = PropertyHelper.parseStringToProperty(YqHotelMgr.getJinHunBiReward(counterConfig.getConsume()));
            player.getModule(CurrencyModule.class).removeCurrency(reward, eLogMoneyType.YQHotel,eLogMoneyType.YqHotelActivityBuildingLevelUp);
            result.addConsume(reward);
            setBuildingLevel(buildingId,oLevel + 1);
            userData.setBuildingLevelUpTime(buildingId,oLevel+1,nowTime);
            changeStudentMap = clearWaitTimeSeatUp(nowTime,buildingId,YqHotelMgr.getBuildingSeat(buildingId,oLevel + 1) - YqHotelMgr.getBuildingSeat(buildingId,oLevel));
            YqHotelPassStudentResult passResult = mainLogic(nowTime,true);
            addChangeStudent(changeStudentMap,passResult.getChangeStudent());
            result.setChangeStudent(changeStudentMap);
        }else if(type == 2){
            oLevel = getSkillLevel(buildingId);
            YqHotelSkillConfig nextSkillConfig = YqHotelMgr.getSkillConfig(buildingId,oLevel + 1);
            if(nextSkillConfig == null){
                result.setRet(GameErrorCode.E_YQ_HOTEL_CONFIG_ERR);
                return result;
            }
            YqHotelSkillConfig skillConfig = YqHotelMgr.getSkillConfig(buildingId,oLevel);
            Property reward = PropertyHelper.parseStringToProperty(YqHotelMgr.getJinHunBiReward(skillConfig.getCost()));
            if(!player.getModule(CurrencyModule.class).currencyIsEnough(reward)){
                result.setRet(GameErrorCode.E_BAG_ITEM_NO_ENOUGH);
                return result;
            }
            player.getModule(CurrencyModule.class).removeCurrency(reward, eLogMoneyType.YQHotel,eLogMoneyType.YqHotelActivitySkillLevelUp);
            result.addConsume(reward);
            setSkillLevel(buildingId,oLevel + 1);
            Map<Integer,YqHotelStudentData> changeStudent = skillRedo(nowTime,buildingId);
            result.setChangeStudent(changeStudent);
        }else{
            result.setRet(GameErrorCode.E_YQ_HOTEL_PARAMS_ERR);
            return result;
        }

        notifyActivityLevelUpBuilding();


        LogYqHotelBuilding logYqHotelBuilding = new LogYqHotelBuilding(YqHotelMgr.getActivityTimeAcId(), getUserId(), buildingId, type, oLevel, PropertyHelper.parsePropertyToString(result.getConsume()));
        AutoLogMgr.add(logYqHotelBuilding);

        return result;
    }

    //重新计算魂
    private Map<Integer, YqHotelStudentData> skillRedo(long nowTime, int buildingId){
        //本来只要同步变化的，客户端表示不行
        Map<Integer,YqHotelStudentData> changeStudent = new ConcurrentHashMap<>();
        if(YqHotelMgr.isEnrolBuildingId(buildingId)){
            return changeStudent;
        }
        Map<Integer,Long> buildingStudyTimeMap = YqHotelMgr.getConfig().getBuildingStudyTimeMap();
        Map<Integer,Long> buildingEnterTimeMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        for(YqHotelStudentData student : studentMap.values()){
            Map<Integer,Long> studentBuildingStudyTimeMap = buildingStudyTimeMap;
            Map<Integer,Long> studentBuildingEnterTimeMap = buildingEnterTimeMap;
            if(student.isQuickStudy()){
                studentBuildingStudyTimeMap = student.getStudyTimeMap();
                studentBuildingEnterTimeMap = student.getEnterTimeMap();
            }
            long studentOverStudyTime = student.getStartTime() + studentBuildingEnterTimeMap.get(buildingId) + studentBuildingStudyTimeMap.get(buildingId) + getIncludeBuildingWaitTime(student.getNo(),buildingId);
            if(nowTime < studentOverStudyTime){
                student.getLeftSoulMap().put(buildingId,YqHotelMgr.randomSoulValue(buildingId, getSkillLevel(buildingId)));
                if(student.getType() == 2){
                    student.getRightSoulMap().put(buildingId,YqHotelMgr.randomSoulValue(buildingId, getSkillLevel(buildingId)));
                }
                changeStudent.put(student.getNo(),student);
            }
        }
        userData.setStudentMap(studentMap);
        return changeStudent;
    }

    //升级座位判断是否可行
    public int levelUpPre(int buildingId){
        int oLevel = getBuildingLevel(buildingId);
        YqHotelCounterConfig counterConfig = YqHotelMgr.getBuildingConfig(buildingId,oLevel);
        if(counterConfig == null){
            return GameErrorCode.E_YQ_HOTEL_CONFIG_ERR;
        }
        Property reward = PropertyHelper.parseStringToProperty(YqHotelMgr.getJinHunBiReward(counterConfig.getConsume()));
        if(!player.getModule(CurrencyModule.class).currencyIsEnough(reward)){
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        return 0;
    }

    /**
     * 同步学生
     */
    public void syncStudent(Map<Integer, YqHotelStudentData> studentMap, int type){
        YqHotelProto.YqHotelStudentSyncMsg.Builder syncMsg = parseSyncPb(studentMap,false,type);
        player.sendPacket(ClientProtocol.U_YQ_HOTEL_STUDENT_SYNC, syncMsg);
    }


    /**
     * 获取学生入学时间
     * @param studentId
     * @param buildingId
     * @return
     */
    public long getStudentEnterTime(int studentId,int buildingId){
        YqHotelStudentData student = getStudentData(studentId);
        if(student == null){
            log.error("getStudentEnterTime找不到学生{}",studentId);
            return 0;
        }
        Map<Integer,Long> studentEnterMap = getStudentEnterMap(studentId);
        return student.getStartTime() + studentEnterMap.get(buildingId) + getBeforeBuildingWaitTime(studentId,buildingId);
    }

    public Map<Integer,Integer> getTitleManualMap(){
        return userData.getSolderTitleCountMap();
    }

    /**
     * 没入学流失的学生移除
     * @param nowTime
     * @param studentId
     */

    private void removeStudent(long nowTime,int studentId){
        YqHotelStudentData student = studentMap.get(studentId);
        if(null == student.getNickName()){
            if(nowTime - student.getDieTime() > 60000){
                student.setNickName("离线学生"+studentId);
            }else {
                student.setNickName(NameMgr.getRandomName(eSexType.MALE,player.getLanguage()));
            }
        }
        Map<Integer,Integer> dieCountMap = userData.getDieCountMap();
        student.setDieTime(getStudentLostTime(student));
        if(student.getDieInBuilding() != -1){
            dieCountMap.put(student.getDieInBuilding(),dieCountMap.get(student.getDieInBuilding()) + 1);
        }
        Map<Integer, YqHotelStudentData> cacheDisappearStudentMap = userData.getCacheDisappearMap();
        cacheDisappearStudentMap.put(studentId,student);
        userData.setCacheDisappearMap(cacheDisappearStudentMap);
        studentMap.remove(studentId);
        //太大了
//        userData.setStudentMap(studentMap);
        userData.setDieCountMap(dieCountMap);

        //离线的要算出哪里流失最多
        if(student.getDieInBuilding() != -1){
            if(!offLineTitleCountMap.containsKey(student.getDieInBuilding())){
                offLineTitleCountMap.put(student.getDieInBuilding(),0);
            }
            offLineTitleCountMap.put(student.getDieInBuilding(),offLineTitleCountMap.get(student.getDieInBuilding()) + 1);
        }
    }


    //没有淘汰的学生去学习
    private YqHotelPassStudentResult learnLogic(long nowTime){
        YqHotelPassStudentResult passStudentResult = new YqHotelPassStudentResult();
        Map<Integer,String> solderMap = new ConcurrentHashMap<>();
        List<Integer> graduationList = new ArrayList<>();
        for(YqHotelStudentData student : studentMap.values()){
            YqHotelOneStudentResult graduateRes = oneStudentLearn(nowTime,student);
            if(graduateRes.isBiye()){
                solderMap.put(student.getNo(),graduateRes.getSoulParams());
                graduationList.add(student.getNo());
            }
        }
        passStudentResult.setOfflineSolder(solderMap);
        for(Integer studentId : graduationList){
            removeStudent(nowTime,studentId);
        }
        userData.setStudentMap(studentMap);
        return passStudentResult;
    }

    /**
     * 一个学生学习
     * @param nowTime
     * @param student
     * @return
     */
    private YqHotelOneStudentResult oneStudentLearn(long nowTime, YqHotelStudentData student){
        YqHotelOneStudentResult oneStudentResult = new YqHotelOneStudentResult();
        Map<Integer,Long> buildingEnterTimeMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        for(int buildingId : buildingEnterTimeMap.keySet()){
            if(!student.getLeftSoulMap().containsKey(buildingId)){
                student.getLeftSoulMap().put(buildingId,YqHotelMgr.randomSoulValue(buildingId, getSkillLevel(buildingId)));
            }
            if(student.getType() == 2 && !student.getRightSoulMap().containsKey(buildingId)){
                student.getRightSoulMap().put(buildingId,YqHotelMgr.randomSoulValue(buildingId, getSkillLevel(buildingId)));
            }
        }
        //招待所不会产生魂
        if(nowTime >= getStudentGraduateTime(student)){
//            log.error("{}:学生{}，时间已经毕业,魂获得情况{},开始学习时间{}",DateHelper.getCurrentDateTimeString(),student.getNo(),student.getSoulMap(),DateHelper.getCurrentDateTimeString(student.getStartTime()));
            oneStudentResult.setStudentId(student.getNo());
            oneStudentResult.setBiye(true);
            String soulParams = graduateStudent(student);
            oneStudentResult.setSoulParams(soulParams);
        }
        return oneStudentResult;
    }

    /**
     * 毕业了统计所有的魂生成毕业的学生
     * @param student
     * @return
     */
    private String graduateStudent(YqHotelStudentData student){
        Map<Integer,String> solderMap = userData.getSolderData();
        BigInteger leftSoulValue = BigInteger.ZERO;
        BigInteger rightSoulValue = BigInteger.ZERO;
        for(long buildingSoul : student.getLeftSoulMap().values()){
            leftSoulValue = leftSoulValue.add(BigInteger.valueOf(buildingSoul));
        }
        for(long buildingSoul : student.getRightSoulMap().values()){
            rightSoulValue = rightSoulValue.add(BigInteger.valueOf(buildingSoul));
        }
        String soulParams = leftSoulValue + "|" + rightSoulValue;
        solderMap.put(student.getNo(),soulParams);
        userData.setSolderData(solderMap);

        addTitleMap(leftSoulValue.compareTo(rightSoulValue) > 0 ? leftSoulValue.longValue() : rightSoulValue.longValue());

        return soulParams;
    }

    /**
     * 加头衔 
     */
    private void addTitleMap(long soulValue){
        YqHotelTitleConfig titleConfig = YqHotelMgr.getTitleConfigBySoul(soulValue);
        if(titleConfig == null){
            log.error("斗罗学院存在魂范围不在头衔的值{}",soulValue);
            return;
        }
        Map<Integer, Integer> titleMap = userData.getSolderTitleCountMap();
        if(!titleMap.containsKey(titleConfig.getId())){
            titleMap.put(titleConfig.getId(),0);
        }
        titleMap.put(titleConfig.getId(),titleMap.get(titleConfig.getId()) + 1);
    }
    
    
    /**
     * 获取学生毕业时间
     * @param student
     * @return
     */
    
    private long getStudentGraduateTime(YqHotelStudentData student){
        Map<Integer,Long> buildingStudyTimeMap = YqHotelMgr.getConfig().getBuildingStudyTimeMap();
        Map<Integer,Long> buildingEnterTimeMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        Map<Integer,Long> studentBuildingStudyTimeMap = buildingStudyTimeMap;
        Map<Integer,Long> studentBuildingEnterTimeMap = buildingEnterTimeMap;
        if(student.isQuickStudy()){
            studentBuildingStudyTimeMap = student.getStudyTimeMap();
            studentBuildingEnterTimeMap = student.getEnterTimeMap();
        }
        int lastBuildingId = 0;
        for(int buildingId : buildingStudyTimeMap.keySet()){
            if(buildingId > lastBuildingId){
                lastBuildingId = buildingId;
            }
        }
        long graduateTime = student.getStartTime() + studentBuildingEnterTimeMap.get(lastBuildingId) + studentBuildingStudyTimeMap.get(lastBuildingId) +
                getIncludeBuildingWaitTime(student.getNo(),lastBuildingId);
        return graduateTime;
    }

    /**
     * 获取学生流失时间
     * @param student
     * @return
     */

    private long getStudentLostTime(YqHotelStudentData student){
        if(student.getDieInBuilding() == -1){
            return getStudentGraduateTime(student);
        }
        Map<Integer,Long> buildingEnterTimeMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        Map<Integer,Long> studentBuildingEnterTimeMap = buildingEnterTimeMap;
        if(student.isQuickStudy()){
            studentBuildingEnterTimeMap = student.getEnterTimeMap();
        }
        long graduateTime = student.getStartTime() + studentBuildingEnterTimeMap.get(student.getDieInBuilding()) +
                getIncludeBuildingWaitTime(student.getNo(),student.getDieInBuilding());
        return graduateTime;
    }


    /**
     * 添加更改学生
     * @param studentMap
     * @param student
     */

    private void addChangeStudent(Map<Integer, YqHotelStudentData> studentMap, YqHotelStudentData student){
        if(!studentMap.containsKey(student.getNo())){
            studentMap.put(student.getNo(),student);
        }
    }

    /**
     * 添加更改学生
     * @param studentMap
     */
    private void addChangeStudent(Map<Integer,YqHotelStudentData> studentMap,Map<Integer,YqHotelStudentData> freshStudentMap){
        for(YqHotelStudentData freshStudent : freshStudentMap.values()){
            addChangeStudent(studentMap,freshStudent);
        }
    }
    

    /**
     * 获取离线最大建筑id
     * @return
     */
    public int getOffLineTitleCountMaxBuildingId(){
        int maxBuildingId = 0;
        int maxBuildingCount = 0;
        for(int buildingId : offLineTitleCountMap.keySet()){
            if(isBuildingSeatMax(buildingId)){
                continue;
            }
            if(offLineTitleCountMap.get(buildingId) > maxBuildingCount){
                maxBuildingId = buildingId;
                maxBuildingCount = offLineTitleCountMap.get(buildingId);
            }
        }
        return maxBuildingId;
    }

    public long getBuildingLevelUpTime(int buildingId){
        Map<Integer, Map<Integer, Long>> buildingLevelUpMap = userData.getBuildingLevelUpTimeMap();
        if(!buildingLevelUpMap.containsKey(buildingId)){
            return 0L;
        }
        Map<Integer, Long> upMap = buildingLevelUpMap.get(buildingId);
        return upMap.get(upMap.size());
    }

    public Map<Integer, Map<Integer, Long>> getBuildingLevelUpTimeMap(){
        return userData.getBuildingLevelUpTimeMap();
    }

    private boolean isBuildingSeatMax(int buildingId){
        int buildingLevel = getBuildingLevel(buildingId);
        YqHotelCounterConfig config = YqHotelMgr.getBuildingConfig(buildingId,buildingLevel+1);
        if(config == null){
            return true;
        }
        return false;
    }

    public void syncConfigData(){
        YqHotelProto.YqHotelConfigDataSyncMsg.Builder builder = YqHotelMgr.getConfigBuilder(player.getLanguage());
        if(builder == null){
            return;
        }
        player.sendPacket(Protocol.U_YQ_HOTEL_CONFIG_SYNC, builder);
    }

    public void syncUserData(){
        if (userData == null){
            return;
        }
        YqHotelProto.YqHotelUserDataSyncMsg.Builder syncMsg = parseUserDataSyncPb(userData);
        player.sendPacket(Protocol.U_YQ_HOTEL_USER_DATA_SYNC, syncMsg);
    }

    public void syncUserSolderData(){
        YqHotelProto.YqHotelUserDataSyncMsg.Builder syncMsg = parseUserDataSolderSyncPb(userData);
        player.sendPacket(Protocol.U_YQ_HOTEL_USER_DATA_SYNC, syncMsg);
    }

    private YqHotelProto.YqHotelCollegeEventTemp.Builder parseEventTempPb(YqHotelEventData userEvent){
        YqHotelProto.YqHotelCollegeEventTemp.Builder eventTempMsg = YqHotelProto.YqHotelCollegeEventTemp.newBuilder();
        eventTempMsg.setBuildingId(userEvent.getBuildingId());
        eventTempMsg.setEventId(userEvent.getEventId());
        eventTempMsg.setTime(userEvent.getEventTime());
        return eventTempMsg;
    }

    public YqHotelProto.YqHotelOpenBuildBuildingRespMsg.Builder openBuilding(int buildingId){
        YqHotelProto.YqHotelOpenBuildBuildingRespMsg.Builder msg = YqHotelProto.YqHotelOpenBuildBuildingRespMsg.newBuilder();
        msg.setRet(0);
        Map<Integer,Integer> dieCountMap = userData.getDieCountMap();
        int allCount = 0;
        for(int count : dieCountMap.values()){
            allCount += count;
        }
        msg.setDieCount(allCount);
        msg.setBuildingDieCount(dieCountMap.get(buildingId));
        return msg;
    }

    //清除保存的移除的学生信息
    public void clearCacheDisappearStudent(){
        int minStudentId = 0;
        List<Integer> studentIdList = new ArrayList<>(studentMap.keySet());
        if(studentIdList.size() > 0){
            Collections.sort(studentIdList);
            minStudentId = studentIdList.get(0);
        }
        List<Integer> removeStudentIdList = new ArrayList<>();
        Map<Integer, YqHotelStudentData> cacheDisappearStudentMap = userData.getCacheDisappearMap();
        for(int studentId : cacheDisappearStudentMap.keySet()){
            //多保留一个，不然加速最后以后玩家的时候就找不到了
            if(studentId < minStudentId || cacheDisappearStudentMap.get(studentId).getDieInBuilding() == 1){
                removeStudentIdList.add(studentId);
            }
        }
        for(int studentId : removeStudentIdList){
            cacheDisappearStudentMap.remove(studentId);
        }
        userData.setCacheDisappearMap(cacheDisappearStudentMap);
    }

    public void addHistory(long nowTime,int studentId){
        YqHotelStudentData studentData= getStudentData(studentId);
        String datetime = DateHelper.getCurrentDateTimeString(nowTime);
        if (!debugHistory.containsKey(studentId)){
            debugHistory.put(studentId, new ConcurrentHashMap<>());
        }
        Map<String,String> history = debugHistory.get(studentId);
        if (history.containsKey(datetime)){
            return;
        }
        String debugInfo = "studentId:" + studentId + ",die:" + studentData.getDieInBuilding() +
                ",waitMap:" + (studentData.getWaitMap() == null?"无":studentData.getWaitMap().toString()) +
                ",studyMap:" + (studentData.getStudyTimeMap() == null?"无":studentData.getStudyTimeMap().toString()) + ",";
        history.put(datetime,debugInfo);


    }

    private YqHotelStudentData getStudentData(int studentId){
        if(studentMap.containsKey(studentId)){
            return studentMap.get(studentId);
        }
        if(userData.getCacheDisappearMap().containsKey(studentId)){
            return userData.getCacheDisappearMap().get(studentId);
        }
        log.error(player.getUserId()+"学生"+studentId+"出现找不到了的情况");
        return null;
    }

    //生成事件
    public void timerEventMake(boolean isSync){
        if(!YqHotelMgr.activityInTime()){
            return;
        }
        if (userData == null){
            return;
        }
        if(userData.getLastEventTime() == 0){
            return;
        }
        long nowTime = System.currentTimeMillis();
        long lastEventTime = userData.getLastEventTime();
        long cdTime = YqHotelMgr.getConfig().getYQHOTEL_EVENT_REFRESH_TIME();
        long times = 0;
        if(nowTime - lastEventTime > cdTime){
            times = (nowTime - lastEventTime)/cdTime;
            userData.setLastEventTime(lastEventTime + times * cdTime);
        }
        Map<Integer, YqHotelEventData> eventMap = new ConcurrentHashMap<>();
        for(int i = 0 ; i < times ; i++){
            YqHotelEventData nEvent = YqHotelMgr.randomBuildingEvent(userData.getEventMap(),lastEventTime + (i + 1) * cdTime);
            if(nEvent != null){
                eventMap.put(nEvent.getBuildingId(),nEvent);
                userData.addEvent(nEvent.getBuildingId(),nEvent);
            }
        }
        if(isSync && eventMap.size() > 0){
            YqHotelProto.YqHotelEventSyncMsg.Builder syncMsg = parseEventSyncPb(new ArrayList<>(eventMap.values()));
            player.sendPacket(Protocol.U_YQ_HOTEL_SYNC_EVENT, syncMsg);
        }
    }


    public YqHotelProto.YqHotelDealEventRespMsg.Builder dealEvent(int buildingId, int eventId, int choice){
        YqHotelProto.YqHotelDealEventRespMsg.Builder respMsg = YqHotelProto.YqHotelDealEventRespMsg.newBuilder();
        respMsg.setRet(0);
        YqHotelEventData userEvent = userData.getEventMap().get(buildingId);
        if(userEvent.getEventId() != eventId){
            respMsg.setRet(GameErrorCode.E_YQ_HOTEL_EVENTID_ERR);
            return respMsg;
        }
        List<String> rewardList = YqHotelMgr.getEventConfigRewardList(eventId);
        if(choice <= 0 || choice > rewardList.size()){
            respMsg.setRet(GameErrorCode.E_YQ_HOTEL_EVENT_CHOICE_ERR);
            return respMsg;
        }
        String rewards = rewardList.get(choice-1);
        player.getModule(CurrencyModule.class).addCurrency(rewards,eLogMoneyType.YQHotel,eLogMoneyType.YqHotelActivityEventReward);
        respMsg.setRewards(rewards);

        LogYqHotelEvent logYqHotelEvent = new LogYqHotelEvent(YqHotelMgr.getActivityTimeAcId(), getUserId(), buildingId, eventId, rewards, userEvent.getEventTime(), System.currentTimeMillis());
        AutoLogMgr.add(logYqHotelEvent);

        userEvent.setEventId(0);
        userEvent.setEventTime(0);
        return respMsg;
    }

    public void timerSyncStudent(){
        if(sceneUserId != player.getUserId() || !YqHotelMgr.activityInTime()){
            return;
        }
        synchronized (locker){
            //todo-xx 上线了去掉
//            YqHotelDebugMgr.debugTimerLogic(player);
            mainLogic(System.currentTimeMillis(),true);
        }
    }

    public YqHotelProto.YqHotelEnterBossRespMsg.Builder enterBoss(){
        mainLogic(System.currentTimeMillis(),false);
        YqHotelProto.YqHotelEnterBossRespMsg.Builder enterBossPb = parseEnterBossPb(userData);
        return enterBossPb;
    }

    //考核
    public YqHotelProto.YqHotelSolderTestRespMsg.Builder bossTest(int type , int solderId){
        //有可能没有学生了，会把最新的学生设置成0
        if(userData.getMinSolder() == 0){
            userData.setMinSolder();
        }
        YqHotelBeatBossResult res = new YqHotelBeatBossResult();
        res.setBlood(userData.getBossBlood());
        YqHotelProto.YqHotelSolderTestRespMsg.Builder testRespPb = YqHotelProto.YqHotelSolderTestRespMsg.newBuilder();
        testRespPb.setRet(0);
        if(userData.getBossId() == 0){
            testRespPb.setRet(GameErrorCode.E_YQ_HOTEL_BOSS_ALL_DIE);
            return testRespPb;
        }
        YqHotelProto.YqHotelBossTemp.Builder bossTempPb = YqHotelProto.YqHotelBossTemp.newBuilder();
        if(type == 1){//一个学生打
            if(solderId != userData.getMinSolder()){
                testRespPb.setRet(GameErrorCode.E_YQ_HOTEL_TEST_STUDENT_ERR);
                return testRespPb;
            }
            beatBoss(solderId,res);
        }else if(type == 2){//一键一直打下去到的solderId
            if(!userData.getSolderData().containsKey(solderId)){
                testRespPb.setRet(GameErrorCode.E_YQ_HOTEL_TEST_STUDENT_ERR);
                return testRespPb;
            }
            if(userData.getIntegral() < YqHotelMgr.getCollegeBattleQuickOpenLimit()){
                testRespPb.setRet(GameErrorCode.E_YQ_HOTEL_TEST_ONEKEY_LIMIT);
                return testRespPb;
            }
            Map<Integer,String> tempSolderMap = new ConcurrentHashMap<>(userData.getSolderData());
            List<Integer> solderIdList = new ArrayList<>(tempSolderMap.keySet());
            Collections.sort(solderIdList);
            for(int beatSolderId : solderIdList){
                beatBoss(beatSolderId,res);
                if(res.isDie() || res.getEndSolderId() == solderId){
                    break;
                }
            }
        }
        //把惊魂币提取出来加积分
        Property bossRewards = res.getBossRewards();
        Property solderRewards = res.getSolderRewards();
        int yqhotelScoreItemId = YqHotelMgr.getConfig().getYQHOTEL_SCORE_ITEM_ID();
        BigInteger addJifen = bossRewards.getCountByGoodsId(yqhotelScoreItemId);
        addJifen = addJifen.add(solderRewards.getCountByGoodsId(yqhotelScoreItemId));
        addScore(addJifen);
        if(res.isDie()){
            player.getModule(CurrencyModule.class).addCurrency(res.getBossRewards(),eLogMoneyType.YQHotel,eLogMoneyType.YqHotelActivityKillBoss);
        }
        player.getModule(CurrencyModule.class).addCurrency(res.getSolderRewards(),eLogMoneyType.YQHotel,eLogMoneyType.YqHotelActivitySolderBeat);
        testRespPb.setSolder(parseSolderPb(res.getEndSolderId(),userData.getSolderData().getOrDefault(res.getEndSolderId(),"0|0")));
        bossTempPb.setBossId(userData.getBossId());
        bossTempPb.setBlood(userData.getBossBlood().longValue());
        bossTempPb.setTimes(userData.getBossKillTimes());
        testRespPb.setBoss(bossTempPb);
        testRespPb.setRewards(PropertyHelper.parsePropertyToString(res.getBossRewards()));
        syncUserSolderData();

        Property logReward = new Property();
        logReward.addProperty(solderRewards);
        logReward.addProperty(bossRewards);
        LogYqHotelBoss logYqHotelBoss = new LogYqHotelBoss(YqHotelMgr.getActivityTimeAcId(), getUserId(), res.getStudentCount(), res.getBossId(), res.getBlood().toString(), res.getBeatBlood().toString(), res.isDie(), PropertyHelper.parsePropertyToString(logReward));
        AutoLogMgr.add(logYqHotelBoss);
        return testRespPb;
    }

    //打boss
    private void beatBoss(int solderId, YqHotelBeatBossResult res){
        res.addStudentCount();
        if(res.getStartSolderId() == 0){
            res.setStartSolderId(solderId);
            res.setBossId(userData.getBossId());
        }
        Map<Integer,String> solderMap = userData.getSolderData();
        String soulParams = solderMap.get(solderId);
        List<BigInteger> soulList = StringUtils.stringToBigIntegerList(soulParams,"\\|");
        BigInteger leftSoulValue = soulList.get(0);
        BigInteger rightSoulValue = soulList.get(1);
        BigInteger soulValue = soulList.get(0).add(soulList.get(1));
        BigInteger blood = userData.getBossBlood();
        BigInteger beatBlood = BigInteger.ZERO;
        if(soulValue.compareTo(blood) >= 0){
            beatBlood = blood;
            res.addBeatBlood(blood);
            if(leftSoulValue.compareTo(blood) > 0){
                solderMap.put(solderId,leftSoulValue.subtract(blood).longValue() + "|" + rightSoulValue.longValue());
            }else if(soulValue.compareTo(blood) > 0){
                solderMap.put(solderId,"0|" + rightSoulValue.subtract(blood.subtract(leftSoulValue)).longValue());
            }else{
                solderMap.remove(solderId);
            }
            res.setDie(true);
            res.addBossRewards(YqHotelMgr.getBossRewards(userData.getBossId()));
            if(userData.getBossKillTimes() < YqHotelMgr.getBossKillTimes(userData.getBossId())){
                userData.setBossKillTimes(userData.getBossKillTimes() + 1);
            }else{
                userData.setBossId(YqHotelMgr.getNextBossId(userData.getBossId()));
                userData.setBossKillTimes(1);
            }
            //boss死光了
            if(userData.getBossId() != 0){
                userData.setBossBlood(YqHotelMgr.getBossBlood(userData.getBossId()));
            }else{
                userData.setBossBlood(BigInteger.ZERO);
            }
        }else{
            beatBlood = soulValue;
            res.addBeatBlood(soulValue);
            userData.setBossBlood(blood.subtract(soulValue));
            solderMap.remove(solderId);
        }
        if(leftSoulValue.compareTo(BigInteger.ZERO) > 0){
            Property leftReward = YqHotelMgr.getSolderBeatRewards(soulList.get(0).longValue());
            res.addSolderRewards(leftReward);
        }
        //大的血量大于左手魂，说明右手也打了，加上右手打的奖励
        if(beatBlood.compareTo(BigInteger.valueOf(soulList.get(0).longValue())) > 0){
            Property rightReward = YqHotelMgr.getSolderBeatRewards(soulList.get(1).longValue());
            res.addSolderRewards(rightReward);
        }
        userData.setSolderData(solderMap);
        userData.setMinSolder();
        res.setEndSolderId(solderId);
    }
    public void addScore(BigInteger value){
        userData.setIntegral(userData.getIntegral() + value.longValue());
        notifyActivityScoreCrossRank();
    }
    
    private int getForwardStudent(int studentId){
        List<Integer> studentIdList = new ArrayList<>(studentMap.keySet());
        Collections.sort(studentIdList);
        int index = studentIdList.indexOf(studentId);
        if(index - 1 > 0){
            return studentIdList.get(index-1);
        }
        return 0;
    }

    //目前快速学习只会毕业第一个会毕业的学生，不会发生插队
    public YqHotelQuickStudentResult quickGraduate(long nowTime, int activityId, int studentId){
        Map<Integer, YqHotelStudentData> clearStudentMap = new ConcurrentHashMap<>();
        mainLogic(nowTime,true);
        YqHotelQuickStudentResult res = new YqHotelQuickStudentResult();
        if(YqHotelMgr.getActivityTimeAcId() != activityId){
            res.setRet(GameErrorCode.E_ACTIVITY_OVER_TIME);
            return res;
        }
        YqHotelStudentData student = studentMap.get(studentId);
        if(null == student){
            res.setRet(GameErrorCode.E_YQ_HOTEL_STUDENT_ERR);
            return res;
        }
        int whereStudent = whereisStudent(nowTime,student);
        if(whereStudent == 0){
            res.setRet(GameErrorCode.E_YQ_HOTEL_STUDENT_NOT_STUDY);
            return res;
        }
        int forwardStudentId = getForwardStudent(studentId);
        if(forwardStudentId != 0){
            YqHotelStudentData forwardStudent = studentMap.get(forwardStudentId);
            int whereForwardStudent = whereisStudent(nowTime,forwardStudent);
            if(whereForwardStudent == whereStudent){
                res.setRet(GameErrorCode.E_YQ_HOTEL_STUDENT_NOT_COLLEGE_FIRST);
                return res;
            }
        }
        if(!student.isQuickStudy()){
            Map<Integer,Long> studyTimeMap = new ConcurrentHashMap<>(YqHotelMgr.getConfig().getBuildingStudyTimeMap());
            Map<Integer,Long> enterTimeMap = new ConcurrentHashMap<>(YqHotelMgr.getConfig().getBuildingEnterTimeMap());
            student.setStudyTimeMap(studyTimeMap);
            student.setEnterTimeMap(enterTimeMap);
        }

        long studentEnterTime = student.getStartTime() + student.getEnterTimeMap().get(whereStudent) + getBeforeBuildingWaitTime(studentId,whereStudent);
        long studentStartStudyTime = student.getStartTime() + student.getEnterTimeMap().get(whereStudent) + getIncludeBuildingWaitTime(studentId,whereStudent);

//        long reduceStudyTime = student.getStudyTimeMap().get(whereStudent) - (nowTime - studentStartStudyTime);
        Property reward = YqHotelMgr.getAccelerateTimeCost(student.getLeftSoulMap(),student.getRightSoulMap(),whereStudent);
        if(!player.getModule(CurrencyModule.class).currencyIsEnough(reward)){
            res.setRet(GameErrorCode.E_BAG_ITEM_NO_ENOUGH);
            return res;
        }
        player.getModule(CurrencyModule.class).removeCurrency(reward, eLogMoneyType.YQHotel,eLogMoneyType.YqHotelActivityStudentAccelerate);
        student.setStudyTime(whereStudent,nowTime - studentStartStudyTime);
        student.addQuickBuilding(whereStudent);
        clearStudentMap = clearWaitTimeQuickStudy(nowTime,whereStudent,studentId);
        userData.setStudentMap(studentMap);
        res.setStudent(student);
        YqHotelPassStudentResult resPass = mainLogic(nowTime,true);
        addChangeStudent(clearStudentMap,resPass.getChangeStudent());
        res.setChangeStudent(clearStudentMap);
        return res;
    }

   

    /**
     * @param qsBuildingId 加速的学生所在的建筑id
     * @param qsStudentId
     */
    private Map<Integer, YqHotelStudentData> clearWaitTimeQuickStudy(long nowTime, int qsBuildingId, int qsStudentId){
        Map<Integer,YqHotelStudentData> changeStudentMap = new ConcurrentHashMap<>();
        Map<Integer,Long> buildingEnterTimeMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        List<Integer> buildingIdList = new ArrayList<>(buildingEnterTimeMap.keySet());
        List<Integer> studentIdList = new ArrayList<>(studentMap.keySet());
        Collections.sort(buildingIdList);
        Collections.reverse(buildingIdList);
        Collections.sort(studentIdList);

        clearClearMap();
        boolean firstWaitStudentChange = false;
        for(Integer studentId : studentIdList){
            if(studentId < qsStudentId)continue;
            YqHotelStudentData student = studentMap.get(studentId);
            Map<Integer,Long> studentBuildingEnterTimeMap = buildingEnterTimeMap;
            if(student.isQuickStudy()){
                studentBuildingEnterTimeMap = student.getEnterTimeMap();
            }
            for(Integer buildingId : buildingIdList){
                long studentBeginStudyTime = student.getStartTime() + studentBuildingEnterTimeMap.get(buildingId) + getIncludeBuildingWaitTime(student.getNo(),buildingId);
                long studentEnterCollegeTime = student.getStartTime() + studentBuildingEnterTimeMap.get(buildingId) + getBeforeBuildingWaitTime(student.getNo(),buildingId);
                if(!firstWaitStudentChange && buildingId == qsBuildingId && nowTime > studentEnterCollegeTime && nowTime <= studentBeginStudyTime
                        && !isStudentDieBuilding(nowTime,student,buildingId)){
//                    log.error("加速在等待的第一个学生{},waitMap:{}", student.getNo() ,student.getWaitMap());
                    firstWaitStudentChange = true;
//                    addHistory(nowTime,studentId);
                    long lessTime = studentBeginStudyTime - nowTime;
                    student.getWaitMap().put(buildingId,student.getWaitMap().get(buildingId) - lessTime);
                    student.setDieInBuilding(-1);
                    student.setDieTime(-1);
//                    addClear(nowTime,studentId,buildingId,student.getWaitMap().get(buildingId) - lessTime);
                    addChangeStudent(changeStudentMap,student);

                }else{
                    if(nowTime <= studentBeginStudyTime && !isStudentDieBuilding(nowTime,student,buildingId)){
//                        addHistory(nowTime,studentId);
                        student.setWaitTime(buildingId,-1L);
                        student.setDieInBuilding(-1);
                        student.setDieTime(-1);
//                        addClear(nowTime,studentId,buildingId,0L);
                        addChangeStudent(changeStudentMap,student);
                    }
                }
            }
        }
        userData.setStudentMap(studentMap);
        return changeStudentMap;
    }

    /**
     * 学生是不是流失在建筑
     * @param nowTime
     * @param student
     * @param buildingId
     * @return
     */
    private boolean isStudentDieBuilding(long nowTime, YqHotelStudentData student, int buildingId){
        Map<Integer,Long> studentBuildingEnterTimeMap = getStudentEnterMap(student.getNo());
        long studentEnterCollegeTime = student.getStartTime() + studentBuildingEnterTimeMap.get(buildingId) + getBeforeBuildingWaitTime(student.getNo(),buildingId);
        if(nowTime > studentEnterCollegeTime && student.getDieInBuilding() == buildingId){
            return true;
        }
        if(student.getDieInBuilding() != -1 && student.getDieInBuilding() < buildingId){
            return true;
        }
        return false;
    }
    
    /**
     * 进入场景
     * @param userId
     * @return
     */
    
    public YqHotelProto.YqHotelEnterRespMsg.Builder enterScene(long userId){
        clearOffLineTitleCountMap();
        long nowTime = System.currentTimeMillis();
        sceneUserId = userId;
        if(userData.getProduceTime() == 0){
            userData.setProduceTime(nowTime);
        }
        if(userData.getLastEventTime() == 0){
            userData.setLastEventTime(nowTime);
        }
        long offlineTime = userData.getProduceTime();
        YqHotelPassStudentResult result = mainLogic(nowTime,false);
        YqHotelProto.YqHotelEnterRespMsg.Builder enterPb = parseEnterScenePb(userData,result.getOfflineSolder());
        enterPb.setOffLineTime(offlineTime);
        int maxBuildingId = getOffLineTitleCountMaxBuildingId();
        if(maxBuildingId != 0){
            enterPb.setDieMaxBuilding(maxBuildingId);
        }
        return enterPb;
    }
    
    private YqHotelProto.YqHotelEventSyncMsg.Builder parseEventSyncPb(List<YqHotelEventData> eventList){
        YqHotelProto.YqHotelEventSyncMsg.Builder eventSyncMsg = YqHotelProto.YqHotelEventSyncMsg.newBuilder();
        eventSyncMsg.setActivityId(YqHotelMgr.getActivityTimeAcId());
        for(YqHotelEventData userEvent : eventList){
            eventSyncMsg.addEvents(parseEventTempPb(userEvent));
        }
        return eventSyncMsg;
    }

    public YqHotelProto.YqHotelStudentTemp.Builder parseStudentPb(YqHotelStudentData student){
        initAliveStudent(student);
        YqHotelProto.YqHotelStudentTemp.Builder studentTempMsg = YqHotelProto.YqHotelStudentTemp.newBuilder();
        studentTempMsg.setStudentId(student.getNo());
        studentTempMsg.setName(student.getNickName());
        studentTempMsg.setType(student.getType());
        studentTempMsg.addSoulType(student.getLeftSoulType());
        studentTempMsg.addSoulType(student.getRightSoulType());
        studentTempMsg.setStartTime(student.getStartTime());
        studentTempMsg.setLose(student.getDieInBuilding());
        studentTempMsg.setDebugTime(student.getDieTime());
        List<Integer> buildingIdList = new ArrayList<>(YqHotelMgr.getConfig().getBuildingStudyTimeMap().keySet());
        Map<Integer, Long> buildingWaitMap = student.getWaitMap();
        Map<Integer, Long> leftSoulMap = student.getLeftSoulMap();
        Map<Integer, Long> rightSoulMap = student.getRightSoulMap();
        for(Integer buildingId : buildingIdList){
            YqHotelProto.YqHotelSoulLearnTemp.Builder soulTempMsg = YqHotelProto.YqHotelSoulLearnTemp.newBuilder();
            soulTempMsg.setBuildingId(buildingId);
            soulTempMsg.setLeftSoul(leftSoulMap.containsKey(buildingId)?leftSoulMap.get(buildingId).intValue():0);
            soulTempMsg.setRightSoul(0);
            if(student.getType() == 2){
                soulTempMsg.setRightSoul(rightSoulMap.containsKey(buildingId)?rightSoulMap.get(buildingId).intValue():0);
            }
            studentTempMsg.addSoul(soulTempMsg);
            YqHotelProto.YqHotelBuildingWaitTemp.Builder waitTempMsg = YqHotelProto.YqHotelBuildingWaitTemp.newBuilder();
            waitTempMsg.setBuildingId(buildingId);
            waitTempMsg.setWaitTime(student.isSetWaitTime(buildingId)?student.getWaitTime(buildingId):0);
            studentTempMsg.addBuildingWait(buildingWaitMap.containsKey(buildingId)?buildingWaitMap.get(buildingId).intValue():0);
        }
        if(student.isQuickStudy()){
            Map<Integer,Long> studyTimeMap = student.getStudyTimeMap();
            List<Integer> buildingList = new ArrayList<>(studyTimeMap.keySet());
            Collections.sort(buildingList);
            for(int buildingId : buildingList){
                studentTempMsg.addStudyTime(studyTimeMap.get(buildingId).intValue());
            }
        }
        return studentTempMsg;
    }


    public YqHotelProto.YqHotelSolderTemp.Builder parseSolderPb(int solderId, String soulParams){
        YqHotelProto.YqHotelSolderTemp.Builder solderTempMsg = YqHotelProto.YqHotelSolderTemp.newBuilder();
        solderTempMsg.setStudentId(solderId);
        List<Integer> soulMap = StringUtils.stringToIntegerList(soulParams,"\\|");
        solderTempMsg.setLeftSoul(soulMap.get(0));
        solderTempMsg.setRightSoul(soulMap.get(1));
        return solderTempMsg;
    }

    /**
     *
     * @param syncMap
     * @param isAdd 是不是加学生
     * @param type 1是时间变化的同步 2是魂变化的同步，客户端要用这个来看看是不是要重新计算
     * @return
     */
    public YqHotelProto.YqHotelStudentSyncMsg.Builder parseSyncPb(Map<Integer, YqHotelStudentData> syncMap, boolean isAdd, int type){
        YqHotelProto.YqHotelStudentSyncMsg.Builder respMsg = YqHotelProto.YqHotelStudentSyncMsg.newBuilder();
        respMsg.setType(type);
        respMsg.setActivityId(YqHotelMgr.getActivityTimeAcId());
        respMsg.setIsAdd(isAdd);
        for(YqHotelStudentData student : syncMap.values()){
            respMsg.addStudents(parseStudentPb(student));
        }

        /*if(!isAdd){
            Map<Integer,YqHotelStudentData> disappearStudentMap = new ConcurrentHashMap<>(userData.getCacheDisappearMap());
            for(YqHotelStudentData student : disappearStudentMap.values()){
                respMsg.addStudents(parseStudentPb(student));
            }
        }*/

        return respMsg;
    }

    /**
     * 同步所有学生
     * @param type 1是同步流程变化的，2是同步魂变化的，客户端要计算
     */
    public void syncAllStudent(int type){
        YqHotelProto.YqHotelStudentSyncMsg.Builder builder = parseSyncPb(studentMap, false, type);
        player.sendPacket(ClientProtocol.U_YQ_HOTEL_STUDENT_SYNC,builder);
    }
    

    public YqHotelProto.YqHotelUserDataSyncMsg.Builder parseUserDataSolderSyncPb(YqHotelUserData userData){
        YqHotelProto.YqHotelUserDataSyncMsg.Builder syncMsg = YqHotelProto.YqHotelUserDataSyncMsg.newBuilder();
        syncMsg.setActivityId(YqHotelMgr.getActivityTimeAcId());
        syncMsg.setSolderCount(userData.getSolderData().size());
        return syncMsg;
    }

    /**
     * boss转消息
     * @param userData
     * @return
     */

    public YqHotelProto.YqHotelEnterBossRespMsg.Builder parseEnterBossPb(YqHotelUserData userData){
        YqHotelProto.YqHotelEnterBossRespMsg.Builder respMsg = YqHotelProto.YqHotelEnterBossRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setActivityId(YqHotelMgr.getActivityTimeAcId());
        Map<Integer,String> solderMap = userData.getSolderData();
        for(int solderId : solderMap.keySet()){
            respMsg.addSolders(parseSolderPb(solderId,solderMap.get(solderId)));
        }
        YqHotelProto.YqHotelBossTemp.Builder bossTempMsg = YqHotelProto.YqHotelBossTemp.newBuilder();
        bossTempMsg.setBossId(userData.getBossId());
        bossTempMsg.setBlood(userData.getBossBlood().longValue());
        bossTempMsg.setTimes(userData.getBossKillTimes());
        respMsg.setBoss(bossTempMsg);
        return respMsg;
    }

    /**
     * 玩家数据转同步消息
     * @param userData
     * @return
     */

    public YqHotelProto.YqHotelUserDataSyncMsg.Builder parseUserDataSyncPb(YqHotelUserData userData){
        YqHotelProto.YqHotelUserDataSyncMsg.Builder syncMsg = YqHotelProto.YqHotelUserDataSyncMsg.newBuilder();
        syncMsg.setActivityId(YqHotelMgr.getActivityTimeAcId());
        syncMsg.setSolderCount(userData.getSolderData().size());
        Map<Integer,Integer> buildingLevelMap = userData.getBuildingLevelMap();
        for(int buildingId : buildingLevelMap.keySet()){
            YqHotelProto.YqHotelBuildingTemp.Builder buildingTempMsg = YqHotelProto.YqHotelBuildingTemp.newBuilder();
            buildingTempMsg.setBuildingId(buildingId);
            buildingTempMsg.setBuildingLevel(getBuildingLevel(buildingId));
            buildingTempMsg.setSkillLevel(getSkillLevel(buildingId));
            Map<Integer,Long> timeMap = getBuildingLevelUpTimeMap(buildingId);
            for(long levelUpTime : timeMap.values()){
                buildingTempMsg.addLevelUpTime(levelUpTime);
            }
            syncMsg.addBuildings(buildingTempMsg);
        }
        for(YqHotelEventData userEvent : userData.getEventMap().values()){
            syncMsg.addEvents(parseEventTempPb(userEvent));
        }
        return syncMsg;
    }
    

    public synchronized void initUserData(int activityId){
        YQHotelConfig config = YqHotelMgr.getConfig();
        if(config == null){
            return;
        }
        if (!ActivityMgr.activityInShowTime(config.getActivityInfo())){
            return;
        }
        if(userData == null || userData.getActivityId() != activityId){
            YqHotelUserData tempUserData = new YqHotelUserData();
            tempUserData.setActivityId(activityId);
            tempUserData.setUserId(getUserId());
            tempUserData.setIntegral(0);
            tempUserData.setStudentCount(0);
            tempUserData.setUpdateTime(System.currentTimeMillis());
            Map<Integer, Integer> buildingLevelMap = new ConcurrentHashMap<>();
            Map<Integer, Map<Integer,Long>> buildingLevelUpTimeMap = new ConcurrentHashMap<>();
            Map<Integer, Integer> skillLevelMap = new ConcurrentHashMap<>();
            Map<Integer,Long> buildingStudyTimeMap = config.getBuildingStudyTimeMap();
            Map<Integer, YqHotelEventData> eventMap = new ConcurrentHashMap<>();
            Map<Integer,Integer> dieCountMap = new ConcurrentHashMap<>();
            for(Integer buildingId : buildingStudyTimeMap.keySet()){
                buildingLevelMap.put(buildingId,1);
                skillLevelMap.put(buildingId,1);
                Map<Integer,Long> tempLevelUpMap = new ConcurrentHashMap<>();
                tempLevelUpMap.put(1,1L);
                buildingLevelUpTimeMap.put(buildingId,tempLevelUpMap);
                dieCountMap.put(buildingId,0);
                if(buildingId != config.getEnrolBuildingId()){
                    eventMap.put(buildingId,new YqHotelEventData(buildingId));
                }
            }
            tempUserData.setBuildingLevelMap(buildingLevelMap);
            tempUserData.setSkillLevelMap(skillLevelMap);
            tempUserData.setBuildingLevelUpTimeMap(buildingLevelUpTimeMap);
            tempUserData.setEventMap(eventMap);
            tempUserData.setBossId(YqHotelMgr.getNextBossId(0));
            tempUserData.setBossKillTimes(1);
            tempUserData.setBossBlood(YqHotelMgr.getBossBlood(tempUserData.getBossId()));
            tempUserData.setInsertOption();
//            tempUserData.setLastEventTime(DouLuoYqHoteMgr.getActivityInfo().getBeginTime() * 1000);
//            tempUserData.setProduceTime(DouLuoYqHoteMgr.getActivityInfo().getBeginTime() * 1000);
            tempUserData.setDieCountMap(dieCountMap);
            userData = tempUserData;
            studentMap = new ConcurrentHashMap<>();
        }
    }

    public int getBuildingLevel(int buildingId){
        Map<Integer, Integer> buildingLevelMap = userData.getBuildingLevelMap();
        return buildingLevelMap.get(buildingId);
    }

    public void setBuildingLevel(int buildingId,int level){
        Map<Integer, Integer> buildingLevelMap = userData.getBuildingLevelMap();
        buildingLevelMap.put(buildingId,level);
    }

    public Map<Integer,Long> getBuildingLevelUpTimeMap(int buildingId){
        return userData.getBuildingLevelUpTimeMap().get(buildingId);
    }

    public int getSkillLevel(int buildingId){
        Map<Integer, Integer> skillLevelMap = userData.getSkillLevelMap();
        return skillLevelMap.get(buildingId);
    }

    public void setSkillLevel(int buildingId,int level){
        Map<Integer, Integer> skillLevelMap = userData.getSkillLevelMap();
        skillLevelMap.put(buildingId,level);
    }

    /**
     * 系统解锁
     */
    public void initSystem() {
        ActivityInfo activityInfo = YqHotelMgr.getActivityInfo();
        if(ActivityMgr.activityInShowTime(activityInfo)){
            initUserData(activityInfo.getActivityId());
            syncConfigData();
            syncUserData();
        }
    }

    public void notifyActivityLevelUpBuilding() {
        ActivityInfo activityInfo = YqHotelMgr.getActivityInfo();
        if (activityInfo != null) {
            player.notifyListener(eGamePlayerEventType.YQHotelBuildingLevelUpTime.getValue(),1L);
        }
    }

    /**
     * 更新排行榜
     */
    private void notifyActivityScoreCrossRank() {
        ActivityInfo activityInfo = YqHotelMgr.getActivityInfo();
        if(activityInfo != null){
            player.notifyListener(eGamePlayerEventType.YQHotelPersonalScoreRank.getValue(), userData.getIntegral());
        }
    }

    //只有活着的发给客户端的才有的数据
    public void initAliveStudent(YqHotelStudentData student){
        if(student.getNickName() == null){
            student.setNickName(NameMgr.getRandomName(eSexType.MALE,player.getLanguage()));
        }
    }

    public YqHotelProto.YqHotelEnterRespMsg.Builder parseEnterScenePb(YqHotelUserData userData, Map<Integer,String> offlineSolderMap){
        YqHotelProto.YqHotelEnterRespMsg.Builder respMsg = YqHotelProto.YqHotelEnterRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setActivityId(YqHotelMgr.getActivityTimeAcId());

        for(YqHotelStudentData student : studentMap.values()){
            respMsg.addStudents(parseStudentPb(student));
        }

        clearCacheDisappearStudent();

        Map<Integer,YqHotelStudentData> disappearStudentMap = new ConcurrentHashMap<>(userData.getCacheDisappearMap());
        for(YqHotelStudentData student : disappearStudentMap.values()){
            respMsg.addStudents(parseStudentPb(student));
        }

        for(int solderId : offlineSolderMap.keySet()){
            respMsg.addOffLineSolders(parseSolderPb(solderId,offlineSolderMap.get(solderId)));
        }

        return respMsg;
    }

    /**
     * 船新版本，学习时间会变，会出现插队
     * @param nowTime
     * @param studentBuildingMap
     * @param buildingStudyTime
     * @param buildingId
     * @param eliminateStudentMap
     * @return
     */
    private Map<Integer, YqHotelStudentData> waitTimeDeadStudentStudyTime(long nowTime, Map<Integer, YqHotelBuildingStudent> studentBuildingMap, long buildingStudyTime, int buildingId, Map<Integer,Boolean> eliminateStudentMap){
        Map<Integer,YqHotelStudentData> changeStudent = new ConcurrentHashMap<>();
        int buildingSeat = YqHotelMgr.getBuildingSeat(buildingId,getBuildingLevel(buildingId));
        int waitSeat = YqHotelMgr.getWaitSeat(buildingId,buildingSeat);
        for(Integer studentId : eliminateStudentMap.keySet()){
            studentBuildingMap.remove(studentId);
        }
        if(studentBuildingMap.size() <= buildingSeat){
            return changeStudent;
        }
        List<YqHotelBuildingStudent> studentList = new ArrayList<>(studentBuildingMap.values());
        studentList.sort(new buildingStudentSort());
        int smallDelPoint = 0;
        int smallWaitPoint = 0;
        int bigDelPoint = buildingSeat + waitSeat;
        int bigWaitPoint = buildingSeat;
        while(bigWaitPoint < studentList.size()){
            if(bigDelPoint == bigWaitPoint){
                YqHotelBuildingStudent smallBS = studentList.get(smallDelPoint);
                YqHotelBuildingStudent bigBS = studentList.get(bigDelPoint);
                int smallDelStudentId = smallBS.getStudentId();
                int bigDelStudentId = bigBS.getStudentId();
                YqHotelStudentData smallStudent = studentMap.get(smallDelStudentId);
                YqHotelStudentData bigStudent = studentMap.get(bigDelStudentId);
                long smallStudentStudyTime = buildingStudyTime;
                if(smallStudent.isQuickStudy()){
                    smallStudentStudyTime = smallStudent.getStudyTimeMap().get(buildingId);
                }
                long smallDelStudentOverStudyTime = smallBS.getEnterTime() + getIncludeBuildingWaitTime(smallDelStudentId,buildingId) + smallStudentStudyTime;
                long bigDelStudentEnterTime = bigBS.getEnterTime() + getBeforeBuildingWaitTime(bigDelStudentId,buildingId);
                //会被淘汰
                if(smallDelStudentOverStudyTime > bigDelStudentEnterTime){
                    if(bigStudent.getDieInBuilding() != buildingId){
                        addChangeStudent(changeStudent,bigStudent);
                        /*log.error("学生{}，触发死亡时间，原本建筑是{}，现在变成{},死亡时间{},等待时间{}",
                                bigDelStudentId,student.getDieInBuilding(),buildingId,bigDelStudentEnterTime,student.getWaitMap());*/
                        bigStudent.setDieInBuilding(buildingId);
                        bigStudent.setDieTime(bigDelStudentEnterTime);
                    }
                    if(nowTime >= bigDelStudentEnterTime){
                        eliminateStudentMap.put(bigDelStudentId,true);
                    }else{
                        eliminateStudentMap.put(bigDelStudentId,false);
                    }
                }else{
                    if(bigStudent.getDieInBuilding() == buildingId){
                        addChangeStudent(changeStudent,bigStudent);
                        bigStudent.setDieInBuilding(-1);
                        bigStudent.setDieTime(getStudentLostTime(bigStudent));
                    }
                    while (eliminateStudentMap.containsKey(studentList.get(++smallDelPoint).getStudentId()));
                }
                bigDelPoint++;
            }else{
                if(eliminateStudentMap.containsKey(studentList.get(bigWaitPoint).getStudentId())){
                    bigWaitPoint++;
                    continue;
                }
                int smallWaitStudentId = studentList.get(smallWaitPoint).getStudentId();
                int bigWaitStudentId = studentList.get(bigWaitPoint).getStudentId();

                boolean isChange = setBuildingWaitTimeStudyTime(nowTime,studentBuildingMap,smallWaitStudentId,bigWaitStudentId,buildingId,buildingStudyTime);
                if(isChange){
                    addChangeStudent(changeStudent,studentMap.get(bigWaitStudentId));
                }
                bigWaitPoint++;
                while (eliminateStudentMap.containsKey(studentList.get(++smallWaitPoint).getStudentId()));
            }
        }
        userData.setStudentMap(studentMap);
        return changeStudent;
    }

    /**
     * 设置建筑等待时间学习时间
     * @param nowTime
     * @param studentBuildingMap
     * @param smallWaitStudentId
     * @param bigWaitStudentId
     * @param buildingId
     * @param buildingStudyTime
     * @return
     */
    private boolean setBuildingWaitTimeStudyTime(long nowTime, Map<Integer, YqHotelBuildingStudent> studentBuildingMap, int smallWaitStudentId, int bigWaitStudentId, int buildingId, long buildingStudyTime){
        YqHotelStudentData smallStudent = studentMap.get(smallWaitStudentId);
        long smallStudentStudyTime = buildingStudyTime;
        if(smallStudent.isQuickStudy()){
            smallStudentStudyTime = smallStudent.getStudyTimeMap().get(buildingId);
        }
        long smallWaitStudentEnterTime = getBeforeBuildingWaitTime(smallWaitStudentId,buildingId) + studentBuildingMap.get(smallWaitStudentId).getEnterTime();
        long smallWaitStudentOverStudyTime = getIncludeBuildingWaitTime(smallWaitStudentId,buildingId) + studentBuildingMap.get(smallWaitStudentId).getEnterTime() + smallStudentStudyTime;
        long bigWaitStudentEnterTime = getBeforeBuildingWaitTime(bigWaitStudentId,buildingId) + studentBuildingMap.get(bigWaitStudentId).getEnterTime();
        YqHotelStudentData student = studentMap.get(bigWaitStudentId);
        long waitTime = 0;
        //已经进去学习了不用算等待时间了
        if(nowTime > bigWaitStudentEnterTime && student.isSetWaitTime(buildingId)){
            return false;
        }
        //必须是进去学院的时候他的上位还在学习没毕业
        if(bigWaitStudentEnterTime >= smallWaitStudentEnterTime && bigWaitStudentEnterTime < smallWaitStudentOverStudyTime){
            waitTime = smallWaitStudentOverStudyTime - bigWaitStudentEnterTime;
        }

        if(student.isSetWaitTime(buildingId) && student.getWaitTime(buildingId) != waitTime){
            List<Integer> quickList = new ArrayList<>(student.getQuickBuilding().keySet());
            log.error("{}:学生{}，设置等待时间出现不一样的，建筑id{},上次等待时间{},这次等待时间{},加速过的位置{}",
                    DateHelper.getCurrentDateTimeString(),bigWaitStudentId,buildingId,student.getWaitMap().get(buildingId),waitTime,StringUtils.listToString(quickList,","));
            log.error("这次用"+smallWaitStudentId+":学习完成时间:"+smallWaitStudentOverStudyTime+"等待时间"+ smallStudent.getWaitMap().toString() +"计算等待时间，"+bigWaitStudentId+"进入时间" + bigWaitStudentEnterTime+"等待时间" + student.getWaitMap().toString());
            log.error(debugLastWait.get(bigWaitStudentId));
        }

        long originTime = student.getWaitTime(buildingId);
        student.setWaitTime(buildingId,waitTime>=0?waitTime:0);
        debugLastWait.put(bigWaitStudentId,"上次用"+smallWaitStudentId+":学习完成时间:"+smallWaitStudentOverStudyTime+"等待时间" + smallStudent.getWaitMap().toString() +"计算等待时间，"+bigWaitStudentId+"进入时间" + bigWaitStudentEnterTime+"等待时间" + student.getWaitMap().toString());
        return originTime != student.getWaitTime(buildingId);
    }

    /**
     * 比较学生id 升序
     */
    static class buildingStudentSort implements Comparator<YqHotelBuildingStudent> {
        @Override
        public int compare(YqHotelBuildingStudent o1, YqHotelBuildingStudent o2) {
            if (o1.getStudentId() == o2.getStudentId()) {
                return 0;
            }
            if (o1.getStudentId() > o2.getStudentId()) {
                return 1;
            }
            return -1;
        }
    }

    /**
     * 船新版本的学习
     * @param nowTime
     * @return
     */
    
    private Map<Integer, YqHotelStudentData> studentLifetimeStudyTimeLogic(long nowTime){
        //变化的学生
        Map<Integer,YqHotelStudentData> changeStudent = new ConcurrentHashMap<>();

        Map<Integer,Long> buildingStudyTimeMap = YqHotelMgr.getConfig().getBuildingStudyTimeMap();
        Map<Integer,Long> buildingEnterTimeMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        //学院 no 时间
        Map<Integer, Map<Integer, YqHotelBuildingStudent>> buildingStudentMap = new ConcurrentHashMap<>();
        buildingStudentMap.put(0,new ConcurrentHashMap<>());
        for(int buildingId : buildingEnterTimeMap.keySet()){
            buildingStudentMap.put(buildingId,new ConcurrentHashMap<>());
        }
        for(YqHotelStudentData student : studentMap.values()){
            long startTime = student.getStartTime();
            YqHotelBuildingStudent bs = new YqHotelBuildingStudent(student.getNo(),startTime);
            buildingStudentMap.get(0).put(student.getNo(),bs);
            for(int buildingId : buildingEnterTimeMap.keySet()){
                YqHotelBuildingStudent bsb = new YqHotelBuildingStudent(student.getNo(),0);
                if(student.isQuickStudy()){
                    bsb.setEnterTime(startTime + student.getEnterTimeMap().get(buildingId));
                }else{
                    bsb.setEnterTime(startTime + buildingEnterTimeMap.get(buildingId));
                }
                buildingStudentMap.get(buildingId).put(student.getNo(),bsb);
            }
        }
        List<Integer> buildingIdList = new ArrayList<>(buildingStudentMap.keySet());
        Collections.sort(buildingIdList);
        Map<Integer,Boolean> eliminateStudentMap = new ConcurrentHashMap<>();
        for(int buildingId : buildingIdList){
            if(buildingId == 0)continue;
            Map<Integer,YqHotelStudentData> overBuildingStudent = waitTimeDeadStudentStudyTime(nowTime,buildingStudentMap.get(buildingId),buildingStudyTimeMap.get(buildingId),buildingId,eliminateStudentMap);
            addChangeStudent(changeStudent,overBuildingStudent);
        }
        //已经在时间点该辍学的直接辍学了
        for(Integer studentId : eliminateStudentMap.keySet()){
            if(eliminateStudentMap.get(studentId)){
                removeStudent(nowTime,studentId);
            }
        }
        for(YqHotelStudentData student : studentMap.values()){
            student.setDieTime(getStudentLostTime(student));
        }
        userData.setStudentMap(studentMap);
        return changeStudent;
    }

    //进入场景计算离线收益跑一次,建筑等级升级重新跑一次，玩家在场景生成新的学生跑一次
    public YqHotelPassStudentResult mainLogic(long nowTime, boolean isSyncNewStudent){
        long startTime = System.currentTimeMillis();
        Map<Integer, YqHotelStudentData> freshStudent = makeStudent(nowTime);
        long makeStudentTime = System.currentTimeMillis() - startTime;
        Map<Integer,YqHotelStudentData> changeStudent = studentLifetimeStudyTimeLogic(nowTime);
        long logicStudentTime = System.currentTimeMillis() - startTime;
        addChangeStudent(changeStudent,freshStudent);
        YqHotelPassStudentResult result = learnLogic(nowTime);
        if(System.currentTimeMillis() - startTime > 1000 || freshStudent.size() > 60){
            log.info("学生生成花费时间{}",makeStudentTime);
            log.info("学生计算花费时间{}",logicStudentTime);
            log.info(player.getUserId()+"学生"+freshStudent.size()+"个花费时间{}",System.currentTimeMillis() - startTime);
        }
        clearCacheDisappearStudent();
        if(isSyncNewStudent && freshStudent.size() > 0){
            YqHotelProto.YqHotelStudentSyncMsg.Builder syncMsg = parseSyncPb(freshStudent,true,1);
            player.sendPacket(Protocol.U_YQ_HOTEL_STUDENT_SYNC, syncMsg);
        }
        if(result.getOfflineSolder().size() > 0){
            syncUserSolderData();
        }
        printStudentLog(nowTime);
        removeChangeStudent(changeStudent,freshStudent);
        result.setChangeStudent(changeStudent);
        return result;
    }

    //产出学生去上学
    public Map<Integer, YqHotelStudentData> makeStudent(long nowTime){
        Map<Integer,YqHotelStudentData> freshStudent = new ConcurrentHashMap<>();
        int studentProduceTime = YqHotelMgr.getStudentSpeed(getSkillLevel(YqHotelMgr.getConfig().getEnrolBuildingId()));
        long lastStudentTime;
        lastStudentTime = userData.getProduceTime();
        if(lastStudentTime == 0){
            userData.setProduceTime(nowTime);
            lastStudentTime = nowTime;
        }
        long produceCount = (nowTime - lastStudentTime)/studentProduceTime;
        if(produceCount > 26000){//加个防内存爆破，按每分钟产6个，3天也就25920个
            produceCount = 26000;
        }
        for(int i = 1 ;i <= produceCount; i++){
            YqHotelStudentData student = initStudent(userData.getStudentCount() + 1,lastStudentTime + i * studentProduceTime);
            studentMap.put(student.getNo(),student);
            freshStudent.put(student.getNo(),student);
            userData.setStudentCount(userData.getStudentCount() + 1);
        }
        userData.setProduceTime(userData.getProduceTime() + produceCount * studentProduceTime);
        //第一次进来生成一个学生
        if(userData.getStudentCount() == 0){
            YqHotelStudentData student = initStudent(userData.getStudentCount() + 1,nowTime);
            studentMap.put(student.getNo(),student);
            userData.setStudentCount(userData.getStudentCount() + 1);
            freshStudent.put(student.getNo(),student);
        }
        return freshStudent;
    }

    /**
     * 初始化学生数据
     * @param no
     * @param startTime
     * @return
     */
    public YqHotelStudentData initStudent(int no , long startTime){
        YqHotelStudentData student = new YqHotelStudentData();
        student.setNo(no);
        Map<Integer,Long> leftSoulMap = new ConcurrentHashMap<>();
        Map<Integer,Long> rightSoulMap = new ConcurrentHashMap<>();
        student.setLeftSoulMap(leftSoulMap);
        student.setRightSoulMap(rightSoulMap);
        student.setType(YqHotelMgr.getShuangTypeRandom(getSkillLevel(YqHotelMgr.getConfig().getSoulCheckBuildingId())));
        student.setLeftSoulType(YqHotelMgr.getRandomSoulType(0));
        student.setRightSoulType(0);
        if(student.getType() == 2){//双生魂
            student.setRightSoulType(YqHotelMgr.getRandomSoulType(student.getLeftSoulType()));
        }
        Map<Integer,Long> waitMap = new ConcurrentHashMap<>();
        student.setWaitMap(waitMap);
        student.setStartTime(startTime);
        return student;
    }

    public long getStudentStartStudyTime(int studentId,int buildingId){
        YqHotelStudentData student = getStudentData(studentId);
        if(student == null){
            log.error("getStudentStudyTime找不到学生{}",studentId);
            return 0;
        }
        Map<Integer,Long> studentEnterMap = getStudentEnterMap(studentId);
        return student.getStartTime() + studentEnterMap.get(buildingId) + getIncludeBuildingWaitTime(studentId,buildingId);
    }

    public long getStudentStudyOverTime(int studentId,int buildingId){
        YqHotelStudentData student = getStudentData(studentId);
        if(student == null){
            log.error("getStudentStudyOverTime找不到学生{}",studentId);
            return 0;
        }
        Map<Integer,Long> studentEnterMap = getStudentEnterMap(studentId);
        Map<Integer,Long> studentStudyMap = getStudentStudyMap(studentId);
        return student.getStartTime() + studentEnterMap.get(buildingId) + getIncludeBuildingWaitTime(studentId,buildingId) + studentStudyMap.get(buildingId);
    }

    private long getEnterTime(YqHotelStudentData student,int buildingId){
        Map<Integer,Long> studentBuildingEnterTimeMap = getStudentEnterMap(student.getNo());
        long enterTime = student.getStartTime() + getBeforeBuildingWaitTime(student.getNo(),buildingId) + studentBuildingEnterTimeMap.get(buildingId);
        return enterTime;
    }

    public Map<Integer,Long> getStudentEnterMap(int studentId){
        YqHotelStudentData student = getStudentData(studentId);
        if(student == null){
            log.error("getStudentEnterMap找不到学生{}",studentId);
            return null;
        }
        Map<Integer,Long> studentEnterMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        if(student.isQuickStudy()){
            studentEnterMap = student.getEnterTimeMap();
        }
        return studentEnterMap;
    }


    /**
     * 打印学生的信息
     * @param nowTime
     */
    public void printStudentLog(long nowTime){
        Map<Integer,List<YqHotelStudentData>> buildingWaitingStudentMap = new ConcurrentHashMap<>();
        Map<Integer,List<YqHotelStudentData>> buildingMoreThanStudentMap = new ConcurrentHashMap<>();
        Map<Integer,Long> buildingEnterMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        Map<Integer,Long> buildingStudyMap = YqHotelMgr.getConfig().getBuildingStudyTimeMap();
        List<Integer> buildingIdList = new ArrayList<>(buildingEnterMap.keySet());
        Collections.sort(buildingIdList);
        Map<Integer, Map<Integer,YqHotelStudentData>> buildingStudentMap = new ConcurrentHashMap<>();
        for(int buildingId : buildingIdList) {
            if(!buildingStudentMap.containsKey(buildingId)){
                buildingStudentMap.put(buildingId,new ConcurrentHashMap<>());
            }
        }
        for(YqHotelStudentData student : studentMap.values()){
            for(int buildingId : buildingIdList){
                if(student.getDieInBuilding() > buildingId){
                    buildingStudentMap.get(buildingId).put(student.getNo(),student);
                }
            }
        }
        for(int buildingId : buildingIdList){
            List<Integer> studentIdList = new ArrayList<>(buildingStudentMap.get(buildingId).keySet());
            Collections.sort(studentIdList);
            for(int i = 0;i<studentIdList.size();i++){
                YqHotelStudentData student = studentMap.get(studentIdList.get(i));
                if(student.getDieInBuilding() > buildingId){
                    continue;
                }
                int j = i + 1;
                while ( j < studentIdList.size()){
                    YqHotelStudentData bigStudent = studentMap.get(studentIdList.get(j));
                    long bigStudentStartStudyTime = getStudentStartStudyTime(bigStudent.getNo(),buildingId);
                    long studentStartStudyTime = getStudentStartStudyTime(student.getNo(),buildingId);
                    if(bigStudent.getDieInBuilding() > buildingId){
                        if(bigStudentStartStudyTime < studentStartStudyTime){
                            log.info("出现插队，{}在建筑{}排在{}前面",bigStudent.getNo(),buildingId,student.getNo());
                        }
                    }else{
                        j++;
                    }
                }
            }
        }

        for(YqHotelStudentData student : studentMap.values()){
            int whereisStudentWait = whereStudentWait(nowTime,student);
            int whereisStudentBuildingId = whereisStudent(nowTime,student);
            if(!buildingMoreThanStudentMap.containsKey(whereisStudentBuildingId)){
                buildingMoreThanStudentMap.put(whereisStudentBuildingId,new ArrayList<>());
            }
            if(!buildingWaitingStudentMap.containsKey(whereisStudentWait)){
                buildingWaitingStudentMap.put(whereisStudentWait,new ArrayList<>());
            }
            if((student.getDieInBuilding() > whereisStudentBuildingId || student.getDieInBuilding() == -1)){
                buildingMoreThanStudentMap.get(whereisStudentBuildingId).add(student);
                buildingWaitingStudentMap.get(whereisStudentWait).add(student);
            }
        }
        //这个时间点在学习的建筑不该出现这么多人
        for (int buildingId : buildingMoreThanStudentMap.keySet()){
            if(buildingId == 0)continue;
            int seat = YqHotelMgr.getBuildingSeat(buildingId,getBuildingLevel(buildingId));
            int studyStudentCount = buildingMoreThanStudentMap.containsKey(buildingId)?buildingMoreThanStudentMap.get(buildingId).size():0;
            int waitStudentCount = buildingWaitingStudentMap.containsKey(buildingId)?buildingWaitingStudentMap.get(buildingId).size():0;
            if(studyStudentCount != seat){
                if(studyStudentCount > seat){
                    //扩建了之后用扩建了之前的时间去加速了？？？
                    log.info(player.getUserId()+"出现学习人数大于座位个数({}),buildingId:{},studyTime:{}s,一样的学生时间信息:",
                            seat,buildingId,YqHotelMgr.getConfig().getBuildingStudyTimeMap().get(buildingId)/1000);
                    for(YqHotelStudentData student : buildingMoreThanStudentMap.get(buildingId)){
                        log.info("studentId:{},startTime:{},waitMap:{},clearWaitMap:{}.studyTime:{},startStudyTime:{}",
                                student.getNo(),student.getStartTime(),student.getWaitMap(),clearWaitMap.get(student.getNo()),student.getStudyTimeMap(), DateHelper.getCurrentDateTimeString(getStartStudyTime(student,buildingId)));
                    }
                }
                if(studyStudentCount < seat && waitStudentCount > 0){
                    //升级会导致出现瞬间有人排队座位没有坐满的情况，不打印
                    boolean noLog = false;
                    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                    for(StackTraceElement e : stackTrace){
                        if(e.getMethodName().equals("levelUp")){
                            noLog = true;break;
                        }
                    }
                    if(noLog)return;
                    log.info(player.getUserId()+"出现学习人数小于座位个数({}),buildingId:{},studyTime:{}s,一样的学生时间信息:",
                            seat,buildingId,YqHotelMgr.getConfig().getBuildingStudyTimeMap().get(buildingId)/1000);
                    for(YqHotelStudentData student : buildingMoreThanStudentMap.get(buildingId)){
                        log.info("studentId:{},startTime:{},waitMap:{},studyTime:{},startStudyTime:{}",
                                student.getNo(),student.getStartTime(),student.getWaitMap(),student.getStudyTimeMap(),DateHelper.getCurrentDateTimeString(getStartStudyTime(student,buildingId)));
                    }
                }
                if(studyStudentCount > seat || (studyStudentCount < seat && waitStudentCount > 0)){
                    for(YqHotelStudentData student : buildingMoreThanStudentMap.get(buildingId)){
                        log.info(player.getUserId()+"在学习的id:{},开时:{},挂在{},等时{},在建筑{},是否等{}",
                                student.getNo(),DateHelper.getCurrentDateTimeString(student.getStartTime()),student.getDieInBuilding(),student.getWaitMap(),
                                whereisStudent(nowTime,student), whereStudentWait(nowTime,student));
                    }
                    for(YqHotelStudentData student : buildingMoreThanStudentMap.get(buildingId)){
                        log.info(player.getUserId()+"等待的id:{},开时:{},挂在{},等时{},在建筑{},是否等{}",
                                student.getNo(),DateHelper.getCurrentDateTimeString(student.getStartTime()),student.getDieInBuilding(),student.getWaitMap(),
                                whereisStudent(nowTime,student), whereStudentWait(nowTime,student));
                    }
                }
            }
        }
    }

    /**
     * 获取学生开始学习时间
     * @param student
     * @param buildingId
     * @return
     */

    private long getStartStudyTime(YqHotelStudentData student, int buildingId){
        Map<Integer,Long> studentBuildingEnterTimeMap = getStudentEnterMap(student.getNo());
        long studyTime = student.getStartTime() + getIncludeBuildingWaitTime(student.getNo(),buildingId) + studentBuildingEnterTimeMap.get(buildingId);
        return studyTime;
    }

    /**
     * 移除
     * @param studentMap
     * @param removeStudentMap
     */

    private void removeChangeStudent(Map<Integer, YqHotelStudentData> studentMap, Map<Integer,YqHotelStudentData> removeStudentMap){
        for(int studentId : removeStudentMap.keySet()){
            studentMap.remove(studentId);
        }
    }

    //判断学生是不是在排队等待
    public int whereStudentWait(long nowTime, YqHotelStudentData student){
        long startTime = student.getStartTime();
        Map<Integer,Long> buildingEnterTimeMap = YqHotelMgr.getConfig().getBuildingEnterTimeMap();
        Map<Integer,Long> studentBuildingEnterTimeMap = getStudentEnterMap(student.getNo());
        for(int buildingId : buildingEnterTimeMap.keySet()){
            long enterTime = getBeforeBuildingWaitTime(student.getNo(),buildingId) + startTime + studentBuildingEnterTimeMap.get(buildingId);
            if(nowTime > enterTime && nowTime <= enterTime + student.getWaitTime(buildingId) &&
                    (student.getDieInBuilding() == -1 || student.getDieInBuilding() > buildingId)){
                return buildingId;
            }
        }
        return -1;
    }

    //学生当前在那个建筑学习，只有在学习的才会返回建筑id，其他返回0
    public int whereisStudent(long nowTime,YqHotelStudentData student){
        long startTime = student.getStartTime();
        Map<Integer,Long> studentBuildingStudyTimeMap = getStudentStudyMap(student.getNo());
        Map<Integer,Long> studentBuildingEnterTimeMap = getStudentEnterMap(student.getNo());

        for(int buildingId : studentBuildingEnterTimeMap.keySet()){
            long enterTime = getBeforeBuildingWaitTime(student.getNo(),buildingId) + startTime + studentBuildingEnterTimeMap.get(buildingId);
            long startStudyTime = getIncludeBuildingWaitTime(student.getNo(),buildingId) + startTime + studentBuildingEnterTimeMap.get(buildingId);
            if(nowTime > startStudyTime && nowTime <= startStudyTime + studentBuildingStudyTimeMap.get(buildingId) &&
                    (student.getDieInBuilding() == -1 || buildingId < student.getDieInBuilding())){
                return buildingId;
            }
        }
        return 0;
    }

    /**
     * 获取学生学习map
     * @param studentId
     * @return
     */

    public Map<Integer,Long> getStudentStudyMap(int studentId){
        YqHotelStudentData student = getStudentData(studentId);
        if(student == null){
            log.error("getStudentStudyMap找不到学生{}",studentId);
            return null;
        }
        Map<Integer,Long> studentStudyMap = YqHotelMgr.getConfig().getBuildingStudyTimeMap();
        if(student.isQuickStudy()){
            studentStudyMap = student.getStudyTimeMap();
        }
        return studentStudyMap;
    }

    //建筑之前的所有等待时间加起来
    private long getBeforeBuildingWaitTime(int studentId,int buildingId){
        YqHotelStudentData student = getStudentData(studentId);
        Map<Integer, Long> waitMap = student.getWaitMap();
        long waitTime = 0L;
        for(int waitBuildingId : waitMap.keySet()){
            if(waitBuildingId < buildingId){
                waitTime += waitMap.get(waitBuildingId);
            }
        }
        return waitTime;
    }

    //建筑之前的包含建筑所有等待时间加起来
    private long getIncludeBuildingWaitTime(int studentId,int buildingId){
        YqHotelStudentData student = getStudentData(studentId);
        if(student == null){
            log.error("getIncludeBuildingWaitTime找不到学生{}",studentId);
            return 0;
        }
        Map<Integer, Long> waitMap = student.getWaitMap();
        long waitTime = 0L;
        for(int waitBuildingId : waitMap.keySet()){
            if(waitBuildingId <= buildingId){
                waitTime += waitMap.get(waitBuildingId);
            }
        }
        return waitTime;
    }
}
